05. Implementing the Game Mechanic

Implementing the Game Mechanic

Please replace the code in your existing GameLogic.cs script with the updated code provided below.

Please Note the Following

  • The video segment from 1:19 minutes through 2:09 minutes into the video, is incorrect. Please ignore this segment and follow the instructions again starting from 2:10 minutes into the video.
  • At 2:09 minutes into the video, when the instructor adds the GvrAudioSource, you should also uncheck Play On Awake to prevent the audio from playing automatically when the game loads.
  • The GvrViewerMain prefab you see in the Hierarchy during the videos no longer exist in GoogleVR Unity SDK and is now represented by the GvrEditorEmulator prefab.
  • The Main Camera you see in the Hierarchy during the videos will typically be nested as a child of the GvrEditorEmulator prefab.
  • The GvrReticle prefab you see in the Hierarchy during the videos has been renamed GvrReticlePointer.
  • The GazeInputModule script no longer exist in GoogleVR Unity SDK and we recommend using the GvrEventSystem prefab instead of the default Unity EventSystem because this prefab already has the required script components.
  • The stereoscopic view you see in the video while in Game mode is no longer rendered in the Unity Game view due to changes to GoogleVR Unity SDK. However, you can still use Alt + Move Mouse to simulate head rotation and Ctrl + Move Mouse to simulate head tilt.
  • If you find that Alt + Move Mouse and Ctrl + Move Mouse does not respond once you have entered Game mode, it's most likely because the Unity project is using GoogleVR Unity SDK version 1.6. For this versions of GoogleVR Unity SDK the head rotation and tilt simulation does not work while using Unity desktop platform mode. Therefore, you need to use a mobile platform, by going to File > Build Settings... and switching to either iOS or Android platform in the Build Settings popup window.
  • In general, the camera should be nested under a parent gameobject, for example, the GvrEditorEmulator prefab, and have a local position and rotation of 0, 0, 0. To reposition the camera, the parent gameobject should be repositioned and the camera itself should keep its local position and rotation of 0, 0, 0.

Updated GameLogic.cs script

using UnityEngine;
using System.Collections;

public class GameLogic : MonoBehaviour
{
    public GameObject player;
    public GameObject eventSystem;
    public GameObject startUI, restartUI;
    public GameObject startPoint, playPoint, restartPoint;

    // An array to hold the orbs.
    public GameObject[] puzzleSpheres;

    // How many times the orbs light up during the pattern display.
    public int puzzleLength = 5;

    // How many seconds between the orbs light up during the pattern display.
    public float puzzleSpeed = 1f;

    // Variable for storing the order of the pattern display.
    private int[] puzzleOrder;

    // Variable for storing the index during the pattern display.
    private int currentDisplayIndex = 0;

    // Variable for storing the index the player is trying to solve.
    private int currentSolveIndex = 0;

    /* Uncomment the line below during 'A Little More Feedback!' lesson.*/
    //public GameObject failAudioHolder;

    void Start()
    {
        // Update 'player' to be the camera's parent gameobject, i.e. 'GvrEditorEmulator' instead of the camera itself.
        // Required because GVR resets camera position to 0, 0, 0.
        player = player.transform.parent.gameObject;

        // Move the 'player' to the 'startPoint' position.
        player.transform.position = startPoint.transform.position;

        // Set the size of our array to the declared puzzle length.
        puzzleOrder = new int[puzzleLength];

        // Create a random puzzle sequence.
        GeneratePuzzleSequence();
    }

    // Create a random puzzle sequence.
    public void GeneratePuzzleSequence()
    {
        // Variable for storing a random number.
        int randomInt;

        // Loop as many times as the puzzle length.
        for (int i = 0; i < puzzleLength; i++)
        {
            // Generate a random number.
            randomInt = Random.Range(0, puzzleSpheres.Length);

            // Set the current index to the randomly generated number.
            puzzleOrder[i] = randomInt;
        }
    }

    // Begin the puzzle sequence.
    public void StartPuzzle()
    {
        // Disable the start UI.
        startUI.SetActive(false);

        // Move the player to the play position.
        iTween.MoveTo(player,
            iTween.Hash(
                "position", playPoint.transform.position,
                "time", 2,
                "easetype", "linear"
            )
        );

        // Call the DisplayPattern() function repeatedly.
        CancelInvoke("DisplayPattern");
        InvokeRepeating("DisplayPattern", 3, puzzleSpeed);

        // Reset the index the player is trying to solving.
        currentSolveIndex = 0;
    }

    // Reset the puzzle sequence.
    public void ResetPuzzle()
    {
        // Enable the start UI.
        startUI.SetActive(true);

        // Disable the restart UI.
        restartUI.SetActive(false);

        // Move the player to the start position.
        player.transform.position = startPoint.transform.position;

        // Create a random puzzle sequence.
        GeneratePuzzleSequence();
    }

    // Disaplay the
    // Called from StartPuzzle() and invoked repeatingly.
    void DisplayPattern()
    {
        // If we haven't reached the end of the display pattern.
        if (currentDisplayIndex < puzzleOrder.Length)
        {
            Debug.Log("Display index " + currentDisplayIndex + ": Orb index " + puzzleOrder[currentDisplayIndex]);

            // Disable gaze input while displaying the pattern (prevents player from interacting with the orbs).
            eventSystem.SetActive(false);

            // Light up the orb at the current index.
            puzzleSpheres[puzzleOrder[currentDisplayIndex]].GetComponent<LightUp>().PatternLightUp(puzzleSpeed);

            // Move one to the next orb.
            currentDisplayIndex++;
        }
        // If we have reached the end of the display pattern.
        else
        {
            Debug.Log("End of puzzle display");

            // Renable gaze input when finished displaying the pattern (allows player to interacte with the orbs).
            eventSystem.SetActive(true);

            // Reset the index tracking the orb being lit up.
            currentDisplayIndex = 0;

            // Stop the pattern display.
            CancelInvoke();
        }
    }

    // Identify the index of the sphere the player selected.
    // Called from LightUp.PlayerSelection() method (see LightUp.cs script).
    public void PlayerSelection(GameObject sphere)
    {
        // Variable for storing the selected index.
        int selectedIndex = 0;

        // Loop throught the array to find the index of the selected sphere.
        for (int i = 0; i < puzzleSpheres.Length; i++)
        {
            // If the passed in sphere is the sphere at the index being checked.
            if (puzzleSpheres[i] == sphere)
            {
                Debug.Log("Looks like we hit sphere: " + i);

                // Update the index of the passed in sphere to be the same as the index being checked.
                selectedIndex = i;
            }
        }

        // Check if the sphere the player selected is correct.
        SolutionCheck(selectedIndex);
    }

    // Check if the sphere the player selected is correct.
    public void SolutionCheck(int playerSelectionIndex)
    {
        // If the sphere the player selected is the correct sphere.
        if (playerSelectionIndex == puzzleOrder[currentSolveIndex])
        {
            Debug.Log("Correct!  You've solved " + currentSolveIndex + " out of " + puzzleLength);

            // Update the tracker to check the next sphere.
            currentSolveIndex++;

            // If this was the last sphere in the pattern display...
            if (currentSolveIndex >= puzzleLength)
            {
                PuzzleSuccess();
            }
        }
        // If the sphere the player selected is the incorrect sphere.
        else
        {
            PuzzleFailure();
        }
    }

    // Do this when the player solves the puzzle.
    public void PuzzleSuccess()
    {
        // Enable the restart UI.
        restartUI.SetActive(true);

        // Move the player to the restart position.
        iTween.MoveTo(player,
            iTween.Hash(
                "position", restartPoint.transform.position,
                "time", 2,
                "easetype", "linear"
            )
        );
    }

    // Do this when the player selects the wrong sphere.
    public void PuzzleFailure()
    {
        Debug.Log("You failed, resetting puzzle");

        // Get the GVR audio source component on the failAudioHolder and play the audio.
        /* Uncomment the line below during 'A Little More Feedback!' lesson.*/
        //failAudioHolder.GetComponent<GvrAudioSource>().Play();

        // Reset the index the player is trying to solving.
        currentSolveIndex = 0;

        // Begin the puzzle sequence.
        StartPuzzle();
    }
}

Capstone Preview:

Note: The capstone requires completing a series of "Achievements" and getting a total of 500 points in each section (Fundamentals, Completeness, and Challenges).

Gamification Achievement